//扩展函数
(function ($) {
    $.extend({
        //取得全部数据库
        yqDbList: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html"
            };
            var o = $.extend({}, options, opts);
            var formData = new FormData();
            formData.append("action", "dbs");
            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //获取form窗体参数
        yqFormParams: function (opts, callback) {
            var _opt = {
                ajaxUrl: "_db.html",
                dbname: "yqbase",                //数据库
                tbname: "ab_test_m",                //表
                tempno: -1,
            };

            var o = $.extend(_opt, opts);

            var title_opt = {
                ajaxUrl: o.ajaxUrl,
                dbname: o.dbname,                //数据库
                tbname: o.tbname,                //表
                tempno: -1
            };
            if (!(o.ctrlid === undefined)) {
                title_opt.ctrlid = o.ctrlid;
            }
            if (!(o.appno === undefined)) {
                title_opt.appno = o.appno;
            }
            if (!(o.menuno === undefined)) {
                title_opt.menuno = o.menuno;
            }

            $.yqTbTitle(title_opt, function (res) {
                if (res.error == 0) {
                    var titles = res.titles;
                    if (o.tempno == -1) {
                        callback({
                            error: 0,
                            info: "ok",
                            titles: titles,
                            model: JSON.stringify(titles)
                        });
                    } else {
                        var model_opt = {
                            ajaxUrl: o.ajaxUrl,
                            dbname: o.dbname,                //数据库
                            tbname: o.tbname,                //表
                            tempno: o.tempno
                        };
                        if (!(o.ctrlid === undefined)) {
                            model_opt.ctrlid = o.ctrlid;
                        }
                        if (!(o.appno === undefined)) {
                            model_opt.appno = o.appno;
                        }
                        if (!(o.menuno === undefined)) {
                            model_opt.menuno = o.menuno;
                        }

                        $.yqTbModel(model_opt, function (res2) {
                            var edit_model;
                            if (res2.error == 0) {
                                var edit_model = res2.model;
                            } else {
                                edit_model = JSON.stringify(titles);
                            }

                            callback({
                                error: 0,
                                info: "ok",
                                titles: titles,
                                model: edit_model
                            });
                        })
                    }
                } else {
                    callback(res);
                }
            });
        },

        //获取实体表title数据
        yqTbTitle: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                dbname: "yqbase",                //数据库
                tbname: "",                       //表
                tempno: "-1"
            };
            var o = $.extend({}, options, opts);
            o.action = "title";

            var formData = new FormData();
            formData.append("action", o.action);
            formData.append("dbname", o.dbname);
            formData.append("tbname", o.tbname);
            formData.append("tempno", o.tempno);

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //获取实体表mobel数据
        yqTbModel: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                dbname: "yqbase",                //数据库
                tbname: "",                       //表
                tempno: "-1"
            };

            var o = $.extend({}, options, opts);
            o.action = "model";

            var formData = new FormData();
            formData.append("action", o.action);
            formData.append("dbname", o.dbname);
            formData.append("tbname", o.tbname);
            formData.append("tempno", o.tempno);

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //查询,不分页
        yqDbTbSelect: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                dbname: "yqbase",                //数据库
                tbname: "",                       //表
                where: "",
                order: ""
            };

            var o = $.extend({}, options, opts);
            o.action = "select";

            var formData = new FormData();
            formData.append("action", o.action);
            formData.append("dbname", o.dbname);
            formData.append("tbname", o.tbname);
            formData.append("where", o.where == "*" ? "" : o.where);
            formData.append("order", o.order);

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        if (res.error != 0) {
                            alert("错误：数据库：" + o.dbname
                                + ",表"
                                + o.tbname
                                + ",错误："
                                + res.info);
                        }

                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });

        },

        //查询，分页
        yqDbTbPaging: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                dbname: "yqbase",                //数据库
                tbname: "",                       //表
                where: "",
                order: "",
                pagesize: 5,
                pageno: 1
            };

            var o = $.extend({}, options, opts);
            o.action = "paging";

            var formData = new FormData();
            formData.append("action", o.action);
            formData.append("dbname", o.dbname);
            formData.append("tbname", o.tbname);
            formData.append("where", o.where == "*" ? "" : o.where);
            formData.append("order", o.order);
            formData.append("pageSize", o.pagesize);
            formData.append("pageNo", o.pageno);

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        if (res.error != 0) {
                            alert("错误：数据库：" + o.dbname
                                + ",表"
                                + o.tbname
                                + ",错误："
                                + res.info);
                        }

                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //查询,不分页
        yqDbTbRow: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                dbname: "yqbase",                //数据库
                tbname: "",                       //表
                keyid: "sid",
                keyval: ""
            };

            var o = $.extend({}, options, opts);

            o.action = "row";

            var formData = new FormData();
            formData.append("action", o.action);
            formData.append("dbname", o.dbname);
            formData.append("tbname", o.tbname);
            formData.append("keyid", o.keyid);
            formData.append("keyval", o.keyval);

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //取外键值
        /*
                rows: [{ 
                    dbname: "yqbase",      //数据库
                    tbname: "a_test_tb",   //表
                    field:"foreignkey",           //关键字段
                    keyid:"sid",           //关键字段
                    ids: ["id1", "id2"] }, //ids
                { 
                    dbname: "yqbase",
                    tbname: "a_test_tb2", 
                    field:"foreignkey",
                    keyid:"sid",
                    ids: ["id-1", "id-2"] }
                ]
        */
        yqDbTbForienKey: function (opts, callback) {
            var options = {
                ajaxUrl: "_db.html",
                rows: [],
            };

            var o = $.extend({}, options, opts);

            var formData = new FormData();
            formData.append("action", "foreignkey");
            formData.append("json", JSON.stringify(o.rows));

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    callback(res);
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        /*
          rows:[{"action":"add",row:{"name":"name1","code":"code1"}},...]
           添加 
           {
                "action": "add",
                "row": {
                    "name": "name1",
                    ...
                }
            }  

            修改
            {
                "action": "upp",
                "row": {
                    "sid": "sid-1",
                    "name": "name1",
                    ...
                }
            }  

            删除：
            {
                "action": "del",
                "row": {
                    "sid": "sid-6"
                }
            }

            粘贴：
            {
                "action": "paste",
                "row": {
                    "pid_field": "pid",
                    "sid": "sid-6",
                    "pid": "sid-7-1",
                    "pid_old": "sid-7"
                }
            }
            
            移动：
            {
                "action": "move",
                "row": {
                    "binding_field":"mm_id",
                    "mm_id":"aaaaaaaa",
                    "pid_field":"pid",
                    "pid":"bbbbbbbbbbb",
                    "ids": ["sid-1", "sid-4", "sid-3", "sid-2"]
                }
            }
                
            注销：可以应用 修改单一属性值接口
            {
                "action":"upp_",
                "row":{
                    "sid":"sid-1",
                    "isdel":false
                }
            }
            修改单一属性值：
            {
                "action":"upp_",
                "row":{
                    "sid":"sid-1",
                    "name":"name1",
                    "code":"code1"
                }
            }
        */
        yqDbAction: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                dbname: "yqbase",                //数据库
                tbname: "",                      //表
                rows: [],
                fileparm: null                    //文件参数{field_name:"",sto_type:1,sto_name:"12"}
            };

            var o = $.extend({}, options, opts);
            o.action = "action";

            var formData = new FormData();
            formData.append("action", o.action);
            if (o.ctrlid === undefined) {
                formData.append("dbname", o.dbname);
                formData.append("tbname", o.tbname);
            } else {
                formData.append("ctrlid", o.ctrlid);
                formData.append("appno", o.appno);
                formData.append("menuno", o.menuno);
            }

            formData.append("json", JSON.stringify(o.rows));
            //console.log(o.rows, JSON.stringify(o.rows));

            if (!(o.fileparm === null || o.fileparm === "") &&
                typeof o.fileparm == "object") {
                formData.append("fileparm", JSON.stringify(o.fileparm));
            }

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        yqHashBase64: function (str, protocol = 'SHA256') {
            result = str
            switch (protocol) {
                case 'MD5':
                    result = String.fromCharCode(...md5.array(str))
                    break;
                case 'SHA1':
                    result = String.fromCharCode(...sha1.array(str))
                    break;
                case 'SHA224':
                    result = String.fromCharCode(...sha224.array(str))
                    break;
                case 'SHA256':
                    result = String.fromCharCode(...sha256.array(str))
                    break;
            }
            result = btoa(result).replaceAll("\/", "_").replaceAll("+", "-");
            return result;
        },

        //取得全部文件数据库
        yqFileList: function (opts, callback) {
            var options = {
                ajaxUrl: '/_file.html'
            };
            var o = $.extend({}, options, opts);
            var ajaxUrl = o.ajaxUrl;
            $.ajax({
                type: 'post',
                url: ajaxUrl,
                dataType: "json",
                data: { action: "fss" },
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },
        // 文件关联类型列表
        yqFileRelTypes: function (opts, callback) {
            var options = {
                ajaxUrl: '/_file.html',
                sto_type: 2,         //1-数据库存储，2-外部存储
                sto_name: null,       //外部存储库名
            };
            var o = $.extend({}, options, opts);

            var formData = new FormData();
            formData.append("action", "reltypes");
            formData.append("sto_type", o.sto_type);
            formData.append("sto_name", o.sto_name);

            $.yqFormAjax(o.ajaxUrl, formData, function (res) {
                callback(res);
            });
        },
        // 文件关联文件查询
        yqFileRelPaging: function (opts, callback) {
            var options = {
                ajaxUrl: '/_file.html',
                sto_type: 2,         //1-数据库存储，2-外部存储
                sto_name: null,       //外部存储库名
                where: "",
                order: "",
                pagesize: 5,
                pageno: 1
            };
            var o = $.extend({}, options, opts);

            var formData = new FormData();
            formData.append("action", "relpaging");
            formData.append("sto_type", o.sto_type);
            formData.append("sto_name", o.sto_name);
            formData.append("where", o.where);
            formData.append("order", o.order);
            formData.append("pagesize", o.pagesize);
            formData.append("pageno", o.pageno);

            $.yqFormAjax(o.ajaxUrl, formData, function (res) {
                callback(res);
            });
        },
        //未关联文件查询
        yqFileNullPaging: function (opts, callback) {
            var options = {
                ajaxUrl: '/_file.html',
                sto_type: 2,         //1-数据库存储，2-外部存储
                sto_name: null,       //外部存储库名
                where: "",
                order: "",
                pagesize: 5,
                pageno: 1
            };
            var o = $.extend({}, options, opts);

            var formData = new FormData();
            formData.append("action", "nullpaging");
            formData.append("sto_type", o.sto_type);
            formData.append("sto_name", o.sto_name);
            formData.append("where", o.where);
            formData.append("order", o.order);
            formData.append("pagesize", o.pagesize);
            formData.append("pageno", o.pageno);

            $.yqFormAjax(o.ajaxUrl, formData, function (res) {
                callback(res);
            });
        },

        //--文件上传开始 -------
        yqFilesUpload: function (f_titles, a_rows, callback) {
            var r_index = 0;
            var f_index = 0;

            loadRow();

            function loadRow() {
                if (r_index == a_rows.length) {
                    callback(a_rows);
                    return;
                }

                f_index = 0
                loadFile(a_rows[r_index])
            }

            function loadFile(a_row) {
                if (f_index == f_titles.length) {
                    r_index++;
                    loadRow();
                    return;
                }

                if (!(a_row.action == "add" || a_row.action == "upp")) {
                    f_index++;
                    loadFile(a_row);
                    return;
                }

                var f_title = f_titles[f_index];

                if (f_title.field_type == 18) { //文件
                    var fileinfo = a_rows[r_index].row[f_title.field_name];
                    //异步处理文件上传
                    if (!(fileinfo === undefined)) {
                        if (fileinfo.file === undefined) {
                            a_rows[r_index].row[f_title.field_name] = JSON.stringify(fileinfo);
                            f_index++;
                            loadFile(a_row);
                        } else {
                            fileUpLoad(f_title, fileinfo.file, function (res) {
                                if (res.error == 0) {
                                    a_rows[r_index].row[f_title.field_name] = JSON.stringify(res.file);
                                } else {
                                    delete fileinfo.file;
                                    fileinfo.error = res.error;
                                    fileinfo.info = res.info;
                                    fileinfo.name = "fail:" + fileinfo.name;
                                    a_rows[r_index].row[f_title.name] = JSON.stringify(fileinfo);
                                }

                                f_index++;
                                loadFile(a_row);
                            });
                        }
                    } else {
                        a_rows[r_index].row[f_title.field_name] = null;
                        f_index++;
                        loadFile(a_row);
                    }
                } else if (f_title.field_type == 19) { //html
                    var htmlinfo = a_rows[r_index].row[f_title.field_name];
                    if (!(htmlinfo === undefined)) {
                        if (htmlinfo.edit_files === undefined) {
                            if (htmlinfo.html === undefined) {
                                htmlinfo.html = "";
                            }
                            a_rows[r_index].row[f_title.field_name] = JSON.stringify(htmlinfo);
                            f_index++;
                            loadFile(a_row);
                        } else {
                            if (typeof htmlinfo.files != "object") {
                                htmlinfo.files = [];
                            }

                            LoadHtmlFile(f_title, htmlinfo, 0, function (htmlinfo_) {
                                delete htmlinfo_.edit_files;
                                if (htmlinfo_.files.length == 0) {
                                    delete htmlinfo_.files;
                                } else {
                                    //去除重复文件
                                    var files = [];
                                    for (let f_i = 0; f_i < htmlinfo_.files.length; f_i++) {
                                        var f1 = htmlinfo_.files[f_i];
                                        var has_f = false;
                                        for (let f_j = 0; f_j < files.length; f_j++) {
                                            if (f1.sto_type == files[f_j].sto_type &&
                                                f1.sto_name == files[f_j].sto_name &&
                                                f1.sid == files[f_j].sid) {
                                                has_f = true;
                                            }
                                        }
                                        if (!has_f) {
                                            files.push(f1);
                                        }
                                    }
                                    htmlinfo_.files = files;
                                }

                                if (typeof htmlinfo_ == "object") {
                                    a_rows[r_index].row[f_title.field_name] = JSON.stringify(htmlinfo_);
                                } else {
                                    a_rows[r_index].row[f_title.field_name] = null;
                                }

                                f_index++;
                                loadFile(a_row);
                            });

                        }
                    } else {
                        a_rows[r_index].row[f_title.field_name] = null;
                        f_index++;
                        loadFile(a_row);
                    }
                }
            }

            //html 文件上传处理
            function LoadHtmlFile(f_title, htmlinfo, file_index, callback) {
                if (htmlinfo.edit_files.length == file_index) {
                    callback(htmlinfo);
                    return;
                }

                var file_item = htmlinfo.edit_files[file_index];

                fileUpLoad(f_title, file_item.file, function (res) {
                    if (res.error == 0) {
                        var filevalue;
                        if (res.file.sto_type == 1) {
                            filevalue = "!" + res.file.sto_name + "_" + res.file.sid;
                        } else if (res.file.sto_type == 2) {
                            filevalue = "^" + res.file.sto_name + "_" + res.file.sid;
                        }

                        var reg = new RegExp(file_item.blobUri, "g");
                        if (!(htmlinfo.html === undefined)) {
                            htmlinfo.html = htmlinfo.html.replace(reg, filevalue);
                        } else if (!(htmlinfo.code === undefined)) {
                            htmlinfo.code = htmlinfo.code.replace(reg, filevalue);
                        }

                        htmlinfo.files.push(res.file);
                    } else {
                        // delete fileinfo.file;
                        // fileinfo.error = res.error;
                        // fileinfo.info = res.info;
                        // fileinfo.name = "fail:" + fileinfo.name;
                        // a_rows[r_index].row[f_title.name] = JSON.stringify(fileinfo);
                    }

                    LoadHtmlFile(f_title, htmlinfo, file_index + 1, callback);
                });
            }

            function fileUpLoad(f_title, file, callback) {
                if (f_title.sto_type == 2 && f_title.chunk) {
                    $.yqFileChunkUpload(file, {
                        ajaxUrl: '/_file.html',
                        //sto_type: f_title.sto_type,     //1-数据库存储，2-外部存储
                        sto_name: f_title.sto_name,     //外部存储库名
                        // 上传完成
                        success: function (res) {
                            callback(res);
                        },
                    })
                } else {
                    $.yqFileUpload(file, {
                        ajaxUrl: '/_file.html',
                        sto_type: f_title.sto_type,     //1-数据库存储，2-外部存储
                        sto_name: f_title.sto_name,     //外部存储库名
                        // 上传完成
                        success: function (res) {
                            callback(res);
                        },
                    })
                }
            }
        },

        //文件上传
        yqFileUpload: function (file, opts) {
            var options = jQuery.extend({
                ajaxUrl: '/_file.html',
                sto_type: 2,         //1-数据库存储，2-外部存储
                sto_name: null,       //外部存储库名
                // 上传完成
                success: function (res) { },
            }, opts);

            var fileFingerprint = '';
            function upload() {
                var formData = new FormData();
                formData.set('action', 'upload');
                formData.set('sto_type', options.sto_type);
                formData.set('sto_name', options.sto_name);
                formData.set('file', file);
                formData.set('name', file.name);
                formData.set('type', file.type);
                formData.set('size', file.size);
                formData.set('finger', fileFingerprint);
                $.ajax({
                    type: 'post',
                    url: options.ajaxUrl,
                    data: formData,
                    cache: false,
                    processData: false,
                    contentType: false,
                    dataType: 'json',
                    success: function (res) {
                        if (typeof options.success == 'function') {
                            options.success(res);
                        }
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        console.error(errorThrown);
                        if (typeof options.success == 'function') {
                            options.success({ error: 99, info: errorThrown });
                        }
                    }
                });
            }
            var reader = new FileReader();
            reader.onload = function () {
                fileFingerprint = $.yqHashBase64(reader.result, 'SHA256');
                upload();
            }
            reader.readAsArrayBuffer(file);
        },
        //文件上传[分片]
        yqFileChunkUpload: function (file, options) {
            var options = jQuery.extend({
                ajaxUrl: '/_file.html',
                sto_type: 2,              //1-数据库存储，2-外部存储
                sto_name: "sqlite",       //外部存储库名
                perPiece: 1024 * 10,    //每个文件切片大小定为1MB  1024 * 1024
                chunk: function (res) { },
                // 全部上传完成，或者中途报错
                success: function (res) { },
            }, options);

            var fileFingerprint = "";
            // 上传第i片的过程
            function uploadChunk(i) {
                var totalPieces = Math.ceil(file.size / options.perPiece);

                var formData = new FormData();
                formData.set('action', 'chunkupload');
                formData.set('sto_type', options.sto_type);
                formData.set('sto_name', options.sto_name);
                formData.set('name', file.name);
                formData.set('type', file.type);
                formData.set('size', file.size);
                formData.set('finger', fileFingerprint);

                formData.set('chunk_count', totalPieces);
                formData.set('chunk_index', i);

                //formData.set('file', file);

                if (i > -1) {
                    var start = i * options.perPiece;
                    if (start >= file.size) {
                        return;
                    }
                    var end = start + options.perPiece;
                    if (end > file.size) {
                        end = file.size;
                    }
                    var chunk = file.slice(start, end);
                    formData.set('file', chunk, file.name);
                } else {
                    formData.set('file', new Blob(), file.name);
                }
                // ajax上传切片
                $.ajax({
                    url: options.ajaxUrl,
                    type: 'POST',
                    data: formData,
                    cache: false,
                    contentType: false,
                    processData: false,
                    dataType: 'json',
                    success: function (res) {
                        if (res.error == 0) {
                            if (res.finished) {
                                if (typeof options.success == 'function') {
                                    options.success(res);
                                }
                            } else {
                                var nextChunk = parseInt(res.chunk_next); // 服务器返回的下一片序号
                                var chunkSize = parseInt(res.chunk_size); // 服务器返回的下一片序号
                                if (chunkSize > 0) {
                                    options.perPiece = chunkSize
                                }
                                uploadChunk(nextChunk);
                            }
                        } else {
                            if (typeof options.success == 'function') {
                                options.success(res);
                            }
                        }
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        console.error(errorThrown);
                        if (typeof options.success == 'function') {
                            options.success({ error: 99, info: errorThrown });
                        }
                    }
                });
            }

            // 计算文件指纹（SHA-256），异步，需要库crypto-js
            var reader = new FileReader();
            reader.readAsArrayBuffer(file);
            reader.onload = function () {
                fileFingerprint = $.yqHashBase64(reader.result, 'SHA256');
                uploadChunk(-1);
            }
        },

        //文件信息
        yqFileInfo: function (opts, callback) {
            var options = jQuery.extend({
                ajaxUrl: '/_file.html',
                sto_type: 2,         //1-数据库存储，2-外部存储
                sto_name: null,       //外部存储库名
                sid: null,
            }, opts);

            var formData = new FormData();
            formData.set('action', 'fileinfo');
            formData.set('sto_type', options.sto_type);
            formData.set('sto_name', options.sto_name);
            formData.set('sid', sid);
            $.ajax({
                type: 'post',
                url: options.ajaxUrl,
                data: formData,
                cache: false,
                processData: false,
                contentType: false,
                dataType: 'json',
                success: function (res) {
                    callback(res);
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.error(errorThrown);
                    callback({ error: 99, info: errorThrown });
                }
            });
        },
        //--文件上传结束  -------


        //数据导出
        yqDataToExcel: function (opts, callback) {
            var options = {
                header: [
                    { name: "a", title: "A" },
                    { name: "b", title: "B" },
                    { name: "c", title: "C" }],
                data: [
                    { a: "a1", b: "b1", c: 1 },
                    { a: "a2", b: "b2", c: 2 },
                    { a: "a3", b: "b3", c: 3 }],
                mergeCells: [{
                    index: 0,
                    field: "a",
                    rowspan: 2,
                    colspan: 1
                }, {
                    index: 2,
                    field: "a",
                    rowspan: 1,
                    colspan: 2
                }],
                filename: "download.xls",
                ajaxUrl: "/_db.html"
            };
            var o = $.extend({}, options, opts);

            var form = new FormData();
            form.append('action', "toexcel");
            form.append('header', JSON.stringify(o.header));
            form.append('data', JSON.stringify(o.data));
            form.append('mergeCells', JSON.stringify(o.mergeCells));
            form.append('filename', o.filename);

            var xhr = new XMLHttpRequest();
            xhr.open('POST', o.ajaxUrl, true);
            xhr.responseType = 'blob';//返回类型为blob
            xhr.send(form);
            xhr.onload = function (e) {
                if (this.status == 200) {//请求成功执行
                    var blob = new Blob([this.response], {
                        type: "application/vnd.ms-excel"
                    });

                    var aa = document.createElement('a');
                    aa.href = URL.createObjectURL(blob);
                    aa.innerHTML = 'link';
                    aa.download = o.filename;
                    aa.style.display = 'none';
                    document.body.appendChild(aa);
                    aa.click();

                    callback({ error: 0, info: "ok" })
                } else {
                    callback({ error: 9, info: "下载失败。" })
                }
            };
        },

        //word数据导出 未完成，待办
        yqDataToWord: function (opts, callback) {
            var options = {
                header: [
                    { name: "a", title: "A" },
                    { name: "b", title: "B" },
                    { name: "c", title: "C" }],
                data: [
                    { a: "a1", b: "b1", c: 1 },
                    { a: "a2", b: "b2", c: 2 },
                    { a: "a3", b: "b3", c: 3 }],
                filename: "download.docx",
                ajaxUrl: "/_db.html"
            };
            var o = $.extend({}, options, opts);

            var form = new FormData();
            form.append('action', "toword");
            form.append('header', JSON.stringify(o.header));
            form.append('data', JSON.stringify(o.data));
            form.append('filename', o.filename);

            var xhr = new XMLHttpRequest();
            xhr.open('POST', o.ajaxUrl, true);
            xhr.responseType = 'blob';//返回类型为blob
            xhr.send(form);
            xhr.onload = function (e) {
                if (this.status == 200) {//请求成功执行
                    var blob = new Blob([this.response], {
                        type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
                    });

                    var aa = document.createElement('a');
                    aa.href = URL.createObjectURL(blob);
                    aa.innerHTML = 'link';
                    aa.download = o.filename;
                    aa.style.display = 'none';
                    document.body.appendChild(aa);
                    aa.click();

                    callback({ error: 0, info: "ok" })
                } else {
                    callback({ error: 9, info: "下载失败。" })
                }
            };
        },


        //取得菜单信息
        yqDbMenus: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                appno: 1                //系统no
            };

            var o = $.extend({}, options, opts);

            var formData = new FormData();
            formData.append("action", "menus");
            formData.append("appno", o.appno);

            $.ajax({
                type: 'POST',
                url: o.ajaxUrl,
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //取得登录状态
        yqLoginstate: function (callback) {
            var formData = new FormData();
            formData.append("action", "loginstate");

            $.ajax({
                type: 'POST',
                url: "/_login.html",
                data: formData,
                processData: false,
                contentType: false,
                dataType: "json",
                success: function (res) {
                    callback(res);
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },
        //退出
        yqLogout: function (callback) {
            $.ajax({
                method: "POST",
                url: "/_login.html",
                dataType: "json",
                data: {
                    action: "logout",
                },
                success: function (res) {
                    callback(res)
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            })
        },

        yqTbInfo: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                action: "tbinfo",
                dbname: "yqbase",                //数据库
                tbname: "",                       //表
            };

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }


            var o = $.extend({}, options, opts);
            var ajaxUrl = o.ajaxUrl;
            delete o.ajaxUrl;
            $.ajax({
                type: 'post',
                url: ajaxUrl,
                dataType: "json",
                data: o,
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        yqTbFields: function (opts, callback) {
            var options = {
                ajaxUrl: "/_db.html",
                action: "tbfields",
                dbname: "yqbase",                //数据库
                tbname: "",                       //表
            };

            var o = $.extend({}, options, opts);

            if (!(o.ctrlid === undefined)) {
                formData.append("ctrlid", o.ctrlid);
            }
            if (!(o.appno === undefined)) {
                formData.append("appno", o.appno);
            }
            if (!(o.menuno === undefined)) {
                formData.append("menuno", o.menuno);
            }

            var ajaxUrl = o.ajaxUrl;
            delete o.ajaxUrl;
            $.ajax({
                type: 'post',
                url: ajaxUrl,
                dataType: "json",
                data: o,
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //获取存储过程模版
        yqProcModel: function (opts, callback) {
            if (!(opts.ajaxUrl === undefined)) {
                delete opts.ajaxUrl;
            }
            if (!(opts.action === undefined)) {
                delete opts.action;
            }

            var options = {
                ajaxUrl: "/_db.html",
                action: "procmodel",
                dbname: "yqbase",                //数据库
                tbname: "",                      //表
                actionval: "add"                  //程序action
            };

            var o = $.extend({}, options, opts);

            var ajaxUrl = o.ajaxUrl;
            delete o.ajaxUrl;
            $.ajax({
                type: 'post',
                url: ajaxUrl,
                dataType: "json",
                data: o,
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //获取存储过程
        yqProcInfo: function (opts, callback) {
            if (!(opts.ajaxUrl === undefined)) {
                delete opts.ajaxUrl;
            }
            if (!(opts.action === undefined)) {
                delete opts.action;
            }

            var options = {
                ajaxUrl: "/_db.html",
                action: "procinfo",
                dbname: "yqbase",                //数据库
                procname: ""                     //存储过程名称
            };

            var o = $.extend({}, options, opts);

            var ajaxUrl = o.ajaxUrl;
            delete o.ajaxUrl;
            $.ajax({
                type: 'post',
                url: ajaxUrl,
                dataType: "json",
                data: o,
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },

        //获取存储过程
        yqProcSave: function (opts, callback) {
            if (!(opts.ajaxUrl === undefined)) {
                delete opts.ajaxUrl;
            }
            if (!(opts.action === undefined)) {
                delete opts.action;
            }

            var options = {
                ajaxUrl: "/_db.html",
                action: "procsave",
                dbname: "yqbase",                //数据库
                proc: ""                         //存储过程
            };

            var o = $.extend({}, options, opts);

            var ajaxUrl = o.ajaxUrl;
            delete o.ajaxUrl;
            $.ajax({
                type: 'post',
                url: ajaxUrl,
                dataType: "json",
                data: o,
                success: function (res) {
                    if ($.yqDataErrCheck(res)) {
                        callback(res);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest.responseText);
                    callback({ "error": 99, "info": errorThrown });
                }
            });
        },
    });
})(jQuery);